package dimension.starry.event;

import dimension.starry.player.ComputedPlayerInfo;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;

public final class Events {

    public static final Event<livingEntityDeath> LIVING_ENTITY_DEATH_EVENT = EventFactory.createArrayBacked(
        livingEntityDeath.class, callbacks -> (livingEntity, source) -> {
            for (livingEntityDeath callback : callbacks) {
                if (!callback.onDeath(livingEntity, source)) {
                    return false;
                }
            }
            return true;
        });
    public static final Event<entityLivingDamageCalc> LIVING_DAMAGE_CALC_EVENT = EventFactory.createArrayBacked(
        entityLivingDamageCalc.class, callbacks -> (entity, damageSource, damageAmount) -> {
            for (entityLivingDamageCalc callback : callbacks) {
                float newDamage = callback.onLivingDamageCalc(entity, damageSource, damageAmount);
                if (newDamage != damageAmount) {
                    return newDamage;
                }
            }
            return -1;
        });
    public static final Event<entityLivingDamage> LIVING_DAMAGE_EVENT = EventFactory.createArrayBacked(
        entityLivingDamage.class, callbacks -> (entity, damageSource, damageAmount) -> {
            float finalAmount = ComputedPlayerInfo.changeDamage(entity, damageSource, damageAmount);
            for (entityLivingDamage callback : callbacks) {
                callback.onLivingDamage(entity, damageSource, finalAmount);
            }
        });
    public static final Event<playerOpenContainer> PLAYER_OPEN_CONTAINER_EVENT = EventFactory.createArrayBacked(
        playerOpenContainer.class, callbacks -> (player, screenHandler) -> {
            for (playerOpenContainer callback : callbacks) {
                if (!callback.onPlayerOpenContainer(player, screenHandler)) {
                    return false;
                }
            }
            return true;
        });
    public static final Event<onHudRender> HUD_RENDER_EVENT = EventFactory.createArrayBacked(
        onHudRender.class, (listeners) -> (drawContext, inGameHud) -> {
            for (onHudRender event : listeners) {
                event.onHudRender(drawContext, inGameHud);
            }
        });
    public static final Event<playerPickupItem> PLAYER_PICKUP_ITEM_EVENT = EventFactory.createArrayBacked(
        playerPickupItem.class, callbacks -> (player, itemEntity) -> {
            for (playerPickupItem callback : callbacks) {
                callback.onPlayerPickupItem(player, itemEntity);
            }
        });
    public static final Event<finishUsingItem> PLAYER_FINISH_USING_ITEM_EVENT = EventFactory.createArrayBacked(
        finishUsingItem.class, callbacks -> (player, itemStack) -> {
            for (finishUsingItem callback : callbacks) {
                callback.onPlayerFinishUsingItem(player, itemStack);
            }
        });
    public static final Event<onCraftItem> PLAYER_CRAFT_ITEM_EVENT = EventFactory.createArrayBacked(
        onCraftItem.class, callbacks -> (player, result) -> {
            for (onCraftItem callback : callbacks) {
                callback.onCraftItem(player, result);
            }
        });
    public static final Event<onWriteDataToLivingEntity> LIVING_WRITE_DATA_EVENT = EventFactory.createArrayBacked(
        onWriteDataToLivingEntity.class, callbacks -> (livingEntity, nbtCompound) -> {
            for (onWriteDataToLivingEntity callback : callbacks) {
                callback.onWriteDataToLivingEntity(livingEntity, nbtCompound);
            }
        });

    private Events() {
    }

    @FunctionalInterface
    public interface livingEntityDeath {
        boolean onDeath(LivingEntity entity, DamageSource source);
    }

    @FunctionalInterface
    public interface entityLivingDamageCalc {
        float onLivingDamageCalc(LivingEntity livingEntity, DamageSource damageSource, float damageAmount);
    }

    @FunctionalInterface
    public interface entityLivingDamage {
        void onLivingDamage(LivingEntity livingEntity, DamageSource damageSource, float damageAmount);
    }

    @FunctionalInterface
    public interface playerOpenContainer {
        boolean onPlayerOpenContainer(ServerPlayerEntity player, ScreenHandler screenHandler);
    }

    @FunctionalInterface
    public interface playerPickupItem {
        void onPlayerPickupItem(PlayerEntity player, ItemEntity item);
    }

    @FunctionalInterface
    public interface finishUsingItem {
        void onPlayerFinishUsingItem(PlayerEntity player, ItemStack itemStack);
    }

    @FunctionalInterface
    public interface onCraftItem {
        void onCraftItem(ServerPlayerEntity player, ItemStack result);
    }

    @FunctionalInterface
    public interface onHudRender {
        void onHudRender(DrawContext drawContext, InGameHud instance);
    }

    @FunctionalInterface
    public interface onWriteDataToLivingEntity {
        void onWriteDataToLivingEntity(LivingEntity livingEntity, NbtCompound nbtCompound);
    }

}
